/*
 * ECARX Technology Limited is the owner of the copyright and the trade secret of this software.
 * Without permission, no one has the right to obtain, disclose or use this software in any way.
 */
package com.ecarx.systemui.plugin.ui.dialog

import android.annotation.SuppressLint
import android.car.VehicleAreaSeat
import android.car.VehicleUnit
import android.car.hardware.CarPropertyValue
import android.car.hardware.property.CarPropertyManager
import android.content.Context
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import android.widget.*
import com.ecarx.systemui.plugin.AppConstants
import com.ecarx.systemui.plugin.R
import com.ecarx.systemui.plugin.controller.hvac.HvacTempController
import com.ecarx.systemui.plugin.controller.hvac.HvacTempController.Companion.getInstance
import com.ecarx.systemui.plugin.model.listener.NoDoubleClickListener
import com.ecarx.systemui.plugin.ui.dialog.base.AutoCloseDialog
import com.ecarx.systemui.plugin.ui.dialog.base.DialogManager
import com.ecarx.systemui.plugin.utils.BitmapUtils
import com.ecarx.systemui.plugin.utils.ClimateTempUtils
import com.ecarx.systemui.plugin.utils.LogUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class DriverTempDialog(private val location: IntArray, context: Context) :
    AutoCloseDialog(context, 0) {
    private var llRoot: LinearLayout? = null
    private var tvTemp: TextView? = null
    private var mTempSeekBar: SeekBar? = null
    private var viewLine: View? = null
    private var flDual: LinearLayout? = null
    private var ivSync: ImageView? = null
    private var tvSync: TextView? = null

    private var tempUnit = VehicleUnit.CELSIUS

    private val tempController: HvacTempController = getInstance()
    private val mArea = VehicleAreaSeat.SEAT_ROW_1_LEFT

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setCancelable(true)
        setCanceledOnTouchOutside(true)
        setContentView(R.layout.dialog_driver_temp)
        initView()
        initConfig()
    }

    private fun initView() {
        llRoot = findViewById(R.id.ll_root)
        tvTemp = findViewById(R.id.tv_temp)
        mTempSeekBar = findViewById(R.id.sb_temp)
        with(mTempSeekBar) { this?.setMax(ClimateTempUtils.getMaxProgress()) }
        viewLine = findViewById(R.id.view_line)
        flDual = findViewById(R.id.fl_dual_view)
        ivSync = findViewById(R.id.iv_sync)
        tvSync = findViewById(R.id.tv_sync)

        registerListener()
        refreshView()
    }

    private fun refreshView() {
        CoroutineScope(Dispatchers.IO).launch {
            val isPowerOn = tempController.isPowerOn()
            if (!isPowerOn) {
                LogUtils.d(TAG, "setPowerOn true")
                tempController.setPowerOn(true)
            }

            val currentTemp = tempController.getCurrentTemp(mArea)
            val syncSupport = tempController.isTempSyncAvailable();
            val isSync = tempController.isTempSync();
            if (tempController.isTempUnitAvailable()) {
                tempUnit = tempController.getTempUnit()
            }
            withContext(Dispatchers.Main) {
                updateAgainShow(currentTemp, syncSupport, isSync, tempUnit);
            }
        }

    }

    private fun setTemp(temp: Float, reason: String) {
        LogUtils.d(TAG, "setTemp:$temp , for $reason")
        CoroutineScope(Dispatchers.IO).launch {
            tempController.setTemp(temp, mArea)
        }
    }

    private fun setTempSync(reason: String) {

        CoroutineScope(Dispatchers.IO).launch {
            val tempSync = !tempController.isTempSync()
            LogUtils.d(TAG, "setTempSync:$tempSync , for $reason")
            tempController.setTempSync(tempSync)
        }
    }


    private fun registerListener() {
        with(mTempSeekBar) {
            this?.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
                override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
                    if (fromUser) {
                        LogUtils.d(TAG, "onProgressChanged:$progress")
                        val tempValue: Float = ClimateTempUtils.getTempByProgress(
                            tempUnit == VehicleUnit.CELSIUS,
                            progress
                        )
                        updateTempText(tempValue, tempUnit)
                        setTemp(tempValue, "seekbar onProgressChanged")
                    }
                }

                override fun onStartTrackingTouch(seekBar: SeekBar) {
                    cancelTimingClose()
                }

                override fun onStopTrackingTouch(seekBar: SeekBar) {
                    startTimingClose()
                    val progress = seekBar.progress
                    LogUtils.d(TAG, "onStopTrackingTouch:$progress")
                    val tempValue: Float = ClimateTempUtils.getTempByProgress(
                        tempUnit == VehicleUnit.CELSIUS,
                        progress
                    )
                    updateTempText(tempValue, tempUnit)
                    setTemp(tempValue, "seekbar stop tracking")
                }
            })
        }
        with(flDual) {
            this?.setOnClickListener(object : NoDoubleClickListener() {
                override fun onNoDoubleClick(view: View) {
                    startTimingClose()
                    setTempSync(" click temp dialog ")
                    refreshView()
                }
            })
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun initConfig() {
        val window = window
        if (window != null) {
            val params = window.attributes
            params.width = WindowManager.LayoutParams.WRAP_CONTENT
            params.height = WindowManager.LayoutParams.WRAP_CONTENT
            params.type = AppConstants.PLUGIN_DIALOG_TYPE
            params.gravity = Gravity.START or Gravity.TOP
            params.dimAmount = 0f
            params.x = location[0] - 1118 / 3
            params.y = location[1] - 176
            window.attributes = params
        }
    }

    override fun delayedDismiss() {
        dismiss()
    }

    private val tempCallback = object : CarPropertyManager.CarPropertyEventCallback {
        override fun onChangeEvent(value: CarPropertyValue<*>?) {
            LogUtils.d(TAG, "tempCallback value:$value")
            refreshView()
        }

        override fun onErrorEvent(p0: Int, p1: Int) {

        }

    }

    private val tempSyncCallback = object : CarPropertyManager.CarPropertyEventCallback {
        override fun onChangeEvent(value: CarPropertyValue<*>?) {
            LogUtils.d(TAG, "tempSyncCallback value:$value")
            refreshView()
        }

        override fun onErrorEvent(p0: Int, p1: Int) {

        }
    }

    private val powerOnCallback = object : CarPropertyManager.CarPropertyEventCallback {
        override fun onChangeEvent(value: CarPropertyValue<*>?) {
            LogUtils.d(TAG, "powerOnCallback value:$value")
            refreshView()
        }

        override fun onErrorEvent(p0: Int, p1: Int) {

        }
    }

    override fun show() {
        super.show()

        CoroutineScope(Dispatchers.IO).launch {
            tempController.registerPowerOnCallback(powerOnCallback)
            tempController.registerTempCallback(tempCallback)
            tempController.registerTempSyncCallback(tempSyncCallback)
        }

    }

    override fun dismiss() {
        llRoot?.startAnimation(outAnimation)
        llRoot?.postDelayed({
            super@DriverTempDialog.dismiss()
            DialogManager.getDialogManager().cleanDriverTempDialog()
        }, 150)

        CoroutineScope(Dispatchers.IO).launch {
            tempController.unRegisterPowerOnCallback(powerOnCallback)
            tempController.unRegisterTempCallback(tempCallback)
            tempController.unRegisterTempSyncCallback(tempSyncCallback)
        }
    }

    fun updateAgainShow(
        driverTempCurrentValue: Float,
        isSupportSync: Boolean,
        isSync: Boolean,
        tempUnit: Int
    ) {
        startTimingClose()
        updateTempAndSyncIsShow(driverTempCurrentValue, isSupportSync, isSync, tempUnit)
    }

    private fun updateTempAndSyncIsShow(
        driverTempValue: Float,
        isSupportSync: Boolean,
        isSync: Boolean,
        tempUnit: Int
    ) {
        this.tempUnit = tempUnit
        if (isSupportSync) {
            updateSyncIcon(isSync)
        } else {
            flDual!!.visibility = View.GONE
            viewLine!!.visibility = View.GONE
//            tvSync!!.text = context.getString(R.string.un_sync)
//            ivSync!!.isSelected = false
        }
        updateTempText(driverTempValue, tempUnit)
        updateProgress(driverTempValue, tempUnit)
    }

    private fun updateProgress(driverTempValue: Float, tempUnit: Int) {
        val progress = tempValueToProgress(driverTempValue, tempUnit)
        LogUtils.d(TAG, "updateProgress: $driverTempValue   tempUnit: $tempUnit")
        mTempSeekBar!!.progress = progress
    }

    private fun tempValueToProgress(driverTempValue: Float, tempUnit: Int): Int {
        return ClimateTempUtils.getProgressByTemp(VehicleUnit.CELSIUS == tempUnit, driverTempValue)
    }

    private fun updateTempText(value: Float?, tempUnit: Int) {
        if (value == null) {
            return
        }
        val MIN_TEMP: Float
        val MAX_TEMP: Float
        if (VehicleUnit.CELSIUS == tempUnit) {
            MIN_TEMP = HvacTempController.MIN_TEMP_C
            MAX_TEMP = HvacTempController.MAX_TEMP_C
        } else {
            MIN_TEMP = HvacTempController.MIN_TEMP_F
            MAX_TEMP = HvacTempController.MAX_TEMP_F
        }
        if (value <= MIN_TEMP) {
            tvTemp!!.setText(R.string.temp_lo)
        } else if (value >= MAX_TEMP) {
            tvTemp!!.setText(R.string.temp_hi)
        } else {
            tvTemp!!.text = value.toString()
        }
    }

    fun updateSyncIcon(isSync: Boolean) {
        LogUtils.d(TAG, "updateSyncIcon:$isSync")
        flDual?.visibility = View.VISIBLE
        viewLine?.visibility = View.VISIBLE
        if (isSync) {
            tvSync?.text = context.getString(R.string.sync)
            ivSync?.setImageBitmap(BitmapUtils.decodeRes(context, R.drawable.ic_nav_hvac_sync))
        } else {
            tvSync?.text = context.getString(R.string.un_sync)
            ivSync?.setImageBitmap(BitmapUtils.decodeRes(context, R.drawable.ic_nav_hvac_unsync))
        }
    }

    companion object {
        private const val TAG = "DriverTempDialog"
    }
}